#pragma once

#include <Eigen/Dense>
#include <vector>
#include "eigen/hidden_layer.h"

namespace  ldl_eigen
{
class Conv2D : public HiddenLayer
{
public:
    using HiddenLayer::forward;
    using HiddenLayer::backward;
    Conv2D(int64_t in_channels, int64_t out_channels, int64_t img_width, 
        int64_t img_height, int64_t kernel_size, int64_t stride = 1, int64_t padding = 0);
    virtual ~Conv2D() = default;

    virtual void forward() override;

    virtual void backward() override;

    virtual void update() override;

    void set_bias(const std::vector<float> bias);
    void set_kernels(const std::vector<Eigen::MatrixXf> &kernels);
private:
    int64_t m_in_channels{};
    int64_t m_out_channels{};
    int64_t m_img_width{};
    int64_t m_img_height{};
    int64_t m_kernel_size{};
    int64_t m_stride{};
    int64_t m_padding{};

    /**
     * @brief 卷积核
     */
    std::vector<Eigen::MatrixXf> m_kernels{};

    /**
     * @brief 损失对卷积核的偏导数
     */
    std::vector<Eigen::MatrixXf> m_kernel_gradients{};

    /**
     * @brief 偏置
     */
    std::vector<float> m_bias;

    /**
     * @brief 损失对偏置的偏导数
     */
    std::vector<float> m_bias_gradient;

    /**
     * @brief 添加padding后的图像宽度
     */
    int64_t m_padding_img_width;

    /**
     * @brief 添加padding后的图像高度
     */
    int64_t m_padding_img_height;

    /**
     * @brief 行滑动的最大值​
     */
    int64_t m_row_sliding_max;

    /**
     * @brief 列滑动的最大值
     */
    int64_t m_col_sliding_max;

    /**
     * @brief 单张图片输出的高度
     */
    int64_t m_output_height;

    /**
     * @brief 单张图片输出的宽度
     */
    int64_t m_output_width;
};
}
